package com.after.saas.common.utils;

import com.after.saas.common.constants.ErrorCodeEnum;
import com.after.saas.common.constants.JwtEnum;
import com.after.saas.common.exception.BaseException;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.ExpiredJwtException;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.apache.commons.lang3.StringUtils;

import java.time.Instant;
import java.time.LocalDateTime;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * @Classname JwtEnum
 * @Date 2021/3/10 15:45
 * @Created by hjchen
 */
public final class JwtUtil {

    private static final String CLAIM_KEY_USERID = "sub";

    /**
     * 签发JWT
     *
     * @param userId 用户id
     * @param secret 加密串
     * @return
     */
    public static String generateToken(String userId, final String secret, JwtEnum jwtEnum) {
        Map<String, Object> claims = new HashMap<>(16);
        claims.put(CLAIM_KEY_USERID, userId);
        return Jwts.builder()
                .setClaims(claims)
                .setExpiration(new Date(Instant.now().toEpochMilli() + jwtEnum.getExpireTime()))
                .signWith(SignatureAlgorithm.HS512, secret)
                .compact();
    }

    /**
     * 获取token是否过期
     */
    public static Boolean isTokenExpired(String token, final String secret) {
        try {
            Date expiration = getExpirationDateFromToken(token, secret);
            return expiration.after(new Date());
        } catch (Exception e) {
            return false;
        }

    }

    /**
     * 根据token获取username
     */
    public static String getUserIdFromToken(String token, final String secret) {
        return getClaimsFromToken(token, secret).getSubject();
    }


    /**
     * 获取token的过期时间
     */
    public static Date getExpirationDateFromToken(String token, final String secret) {
        return getClaimsFromToken(token, secret).getExpiration();
    }

    /**
     * 获取token的过期剩余秒
     *
     * @param token
     * @param secret
     * @return
     */
    public static Long getExpirationSecondLeft(String token, final String secret) {
        return LocalDateUtil.betweenSecond(LocalDateTime.now(),
                LocalDateUtil.date2LocalDateTime(getExpirationDateFromToken(token, secret)));
    }


    /**
     * 解析JWT
     */
    public static Claims getClaimsFromToken(String token, final String secret) {
        if (StringUtils.isEmpty(token)) throw new BaseException(ErrorCodeEnum.ACCESS_TOKEN_EMPTY);
        try {
            return Jwts.parser()
                    .setSigningKey(secret)
                    .parseClaimsJws(token)
                    .getBody();
        } catch (Exception e) {
            if (e instanceof ExpiredJwtException)
                throw new BaseException(ErrorCodeEnum.ACCESS_TOKEN_EXPIRE);
            else throw new BaseException(ErrorCodeEnum.ACCESS_TOKEN_INVALID);
        }
    }

    /**
     * 刷新token
     *
     * @param token  旧token
     * @param secret 加密串
     * @return
     */
    public static String refreshToken(String token, final String secret) {
        String userId = getUserIdFromToken(token, secret);
        return generateToken(userId, secret, JwtEnum.WEB_FRONT);
    }

    public static void main(String[] args) {
//        String token = "eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIyIiwiZXhwIjoxNjI5NzIwMzQ3fQ.gv4_Na1srDIiwvZpyLhw8nPksmtz1pfouKBMtJ6BHfn8k7znb6uym2ZPxfub6awthgrFEaADp7gobOYGHStOPw";
        String secret = "c2t5d29ydGhAcWltczEyMw==";

        String token = JwtUtil.generateToken("1", secret, JwtEnum.WEB_FRONT);
        System.out.println("token = " + token);
        String userId = JwtUtil.getUserIdFromToken(token, secret);
        System.out.println("userId = " + Long.parseLong(userId));
//        System.out.println(JwtUtil.isTokenExpired(token, secret));
//        String refreshToken = JwtUtil.refreshToken(token, secret);
//        System.out.println("新的token:" + refreshToken);
        System.out.println(getClaimsFromToken(token, secret));
        System.out.println("payload:" + JwtUtil.getClaimsFromToken(token, secret).getSubject());
        System.out.println(getExpirationDateFromToken(token, secret));
    }


}
